#include<stdio.h>
#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include<unistd.h>
#include<pthread.h>
#include<signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define   FILEPATH  "/home/damian/Desktop/tmp"
#define    PORT     65001
#define    IP       "192.168.14.82"
#define MSG_LEN     1024
int fd_connected;
int fd_socket;
int TCP_init( int port );
int SendFile ( const char * FileName , int connect_fd );

char filecmd[MSG_LEN];

void *MsgRecv (void *arg)
{
    struct sockaddr_in srcaddr;
    // int fd_socket=*(int*)arg;
    char *buf=calloc(1,MSG_LEN);
    socklen_t addrlen=sizeof(struct sockaddr_in);
    while (1)
    {
       bzero(buf,MSG_LEN);
       recvfrom(fd_socket,buf,MSG_LEN,0,(struct sockaddr *)&srcaddr,&addrlen);
        if(!strncmp(buf,"offline_ok",10))
        {
            break;
        }
        if(!strcmp(buf,"#offline\n"))
        {
            printf("Target was offline\n");
            continue;
        }
          if(!strncmp(buf,"@filesend ",9))
        {   
            char filepath[64];
            char cmd[32];
            char filename[64];
            bzero(filepath,64);
            bzero(cmd,32);
            bzero(filename,64);
            sscanf(buf,"%s %s",cmd,filepath);

            printf("buf--%s\n",buf);
            char *name=strrchr(filepath,'/');
            strcpy(filename,name);
            // printf("crating %s\n",filename);
             printf("name--%s\n",name);
            char *tagdetail=calloc(1,MSG_LEN);
            bzero(tagdetail,MSG_LEN);

            recvfrom(fd_socket,tagdetail,MSG_LEN,0,(struct sockaddr *)&srcaddr,&addrlen);

            char c;
            int tagport;
            char tagip[64];
            bzero(tagip,64);
            sscanf(tagdetail,"%c %s %d",&c,tagip,&tagport);

             // 1. 创建一个用于通行的接口  socket --> 待连接套接字
    fd_connected = socket(AF_INET , SOCK_STREAM , 0 );
    if (fd_connected < 0 )
    {
        perror("socket error");
      
    }
    printf("socket creat successed...\n");
    


    // 2. 配置当前服务器的IP地址等信息
    struct sockaddr_in server_addr = {
        .sin_family =  AF_INET ,   // 协议簇选择IPV4协议
        .sin_port = htons(65002),   // 端口号设置为65000
        .sin_addr.s_addr = inet_addr(tagip) // IP地址 设置为目标服务器的IP地址
        // .sin_addr.s_addr = htonl(INADDR_ANY) // 设置地址为 0  表示当前主机中的任意一个地址都可以
    };


    // 主动发起链接
    socklen_t addrlen = sizeof (server_addr);
    if(connect(fd_connected , (const struct sockaddr *)&server_addr, addrlen))
    {
        perror("connect error");
       
    }
    printf("socket connected...\n");

    char *filepath1=calloc(1,256);
    bzero(filepath1,256);

    snprintf(filepath1,256,"%s%s",FILEPATH,filename);

    char realpath[256];
    bzero(realpath,256);

    snprintf(realpath,strlen(filepath1)+1,"%s",filepath1);

    printf("real_path:%s\n",realpath);
    
    int fd = open(realpath , O_RDWR | O_CREAT | O_TRUNC , 0666  );
    if (fd < 0)
    {
        perror("open file error");
        
    }

    printf("file crate successed\n"  );

    // 向服务器发送确认请求
    send(fd_connected , "OK" , strlen("OK") , 0 );


    int cont = 0 ;
    char *filemsg=calloc(MSG_LEN,1);
   
    while (1)
    {

        bzero(filemsg , MSG_LEN) ;

        int ret_val = read(fd_connected , filemsg, MSG_LEN ) ;
        if ( ret_val <= 0 )
        {
            
        }
        printf("msg:%s\n" , filemsg );
        
        if (!memcmp( filemsg , "End Of File" , ret_val-1  ))
        {
            printf("file translate over，byte=%d\n" , cont );
            break ;
        }
        
        ret_val = write(fd , filemsg , ret_val );

        cont += ret_val ;

        
    }

    // 8. 关闭通信接口
    close(fd_connected );

        }
    // printf("---%d\n",strcmp(buf,"offline_ok\n"));
       printf("%s\n",buf);
      
    }

    close(fd_socket);
    return NULL;
}
void *FileSend(void *arg)
{

    char *cmd=calloc(1,32);
    char *file_sendpath=calloc(1,512);
    char *msg=calloc(1,MSG_LEN);
    char *msg_recv=calloc(1,MSG_LEN);
    bzero(msg_recv,MSG_LEN);
    bzero(msg,MSG_LEN);
    bzero(cmd,32);
    bzero(file_sendpath,512);

    // printf("--msg--%s\n",filecmd);
    strncpy(msg,filecmd,MSG_LEN);
    // printf("--msg--%s\n",msg);
    sscanf(msg,"%s %s",cmd,file_sendpath);


    printf("#--msg--%s,file_sendpath--%s\n",msg,file_sendpath);

    fd_connected=TCP_init(65002);
    if(-1==fd_connected)
    {
        printf("TCP_init failed\n");
    }

    char *msg_flag=calloc(MSG_LEN,1);
    bzero(msg_flag,MSG_LEN);
   int ret_val = recv(fd_connected , msg , MSG_LEN , 0 );
 
     if ( memcmp( msg , "OK\n" , ret_val ))
    {
        printf("第二次收到的内容：%s\n" , msg_flag );
        
    }
    printf("file translating...\n"  );
   

    ret_val = SendFile ( file_sendpath , fd_connected );

    printf("translating over ，byte= %d 字节. \n" , ret_val);

    close(fd_connected);
}
void offline(int sig)
{

     // 设置好需要发送消息的目标地址和端口号
    struct sockaddr_in dest={
            .sin_family=AF_INET,
            .sin_port=htons(PORT),
            // .sin_addr.s_addr= htonl(INADDR_ANY),
            .sin_addr.s_addr=inet_addr(IP)
    };

    sendto(fd_socket,"#offline\n",strlen("#offline\n"), 0,
                        (const struct sockaddr *)&dest, sizeof(dest));

    exit(0);

}



int main(int argc, char const *argv[])
{
   
   signal(2,offline);

    // 创建一个用于通信的网络接口 （获得一个套接字的描述符）
    fd_socket=socket(AF_INET , SOCK_DGRAM, 0);
    if(fd_socket<0)
    {
        perror("socket error..");
        return -1;
    }


     // 设置好需要发送消息的目标地址和端口号
    struct sockaddr_in dest={
            .sin_family=AF_INET,
            .sin_port=htons(PORT),
            // .sin_addr.s_addr= htonl(INADDR_ANY),
            .sin_addr.s_addr=inet_addr(IP)
    };


pthread_t thread;
pthread_create(&thread, NULL,MsgRecv, NULL);

    char *msg=calloc(1,MSG_LEN);

    sendto(fd_socket,"#online\n",strlen("#online\n"), 0,
                        (const struct sockaddr *)&dest, sizeof(dest));

    while (1)
    {
        bzero(msg,MSG_LEN);
       fgets(msg,MSG_LEN,stdin);
       if(!strcmp(msg,"#offline\n"))
       {
            if(sendto(fd_socket,msg,strlen(msg), 0,
                        (const struct sockaddr *)&dest, sizeof(dest))) 
            {
                // printf("send succeed .\n" );
            }
            else{
                perror("send error");
            }
            int errno = pthread_join(thread, NULL);
            if(errno!=0)
            {
                printf("join error :%s\n",strerror(errno));
            }
            else
            {
                printf("Off line successed\n");
                exit(0);
            }

       }
       if(!strncmp(msg,"@filesend ",9))
        {   
            bzero(filecmd,MSG_LEN);
            strcpy(filecmd,msg);
            pthread_t thread1;
            pthread_create(&thread1, NULL,FileSend, NULL);
            // printf("***%s\n",msg);
            sendto(fd_socket,msg,strlen(msg), 0,
                      (const struct sockaddr *)&dest, sizeof(dest));
            
            continue;
        }
       if(sendto(fd_socket,msg,strlen(msg), 0,
                      (const struct sockaddr *)&dest, sizeof(dest))) 
        {
            //  printf("send succeed .\n" );
        }
         else{
            perror("send error");
        }

    }
    

    close(fd_socket);

    return 0;
}



int TCP_init( int port )
{
     // 1. 创建一个用于通行的接口  socket --> 待连接套接字
    int fd_socket = socket(AF_INET , SOCK_STREAM , 0 );
    if (fd_socket < 0 )
    {
        perror("socket error");
        return -1 ;
    }
    printf("socket make successed...\n");

    


    // 2. 配置当前服务器的IP地址等信息
    struct sockaddr_in server_addr = {
        .sin_family =  AF_INET ,   // 协议簇选择IPV4协议
        .sin_port = htons( port ),   // 端口号设置为65000
        // .sin_addr.s_addr = inet_addr(argv[1]) // IP地址 设置为本机的地址即可
        .sin_addr.s_addr = htonl(INADDR_ANY) // 设置地址为 0  表示当前主机中的任意一个地址都可以
    };


    // 3. 把配置号的端口号信息以及 通信接口进行绑定
    socklen_t addrlen = sizeof(server_addr);
    if( bind(fd_socket , (const struct sockaddr *)&server_addr, addrlen))
    {
        perror(" bind error");
        return -1 ;
    }
    printf("socket bind successed...\n");



    // 4. 设置监听 --> 把待连接套接字设置为监听套接字
    if( listen(fd_socket , 0 ))
    {
        perror("listen error");
        return -1 ;
    }
    printf("socket listen successed...\n");

    // 5. 等待客户端链接  --> 通过监听套接字来等待用户链接
    struct sockaddr_in from_addr ;
    int connect_fd = accept(fd_socket , (struct sockaddr *)&from_addr, &addrlen);
    if (connect_fd < 0 )
    {
        perror("connect error");
        return -1 ;
    }
    printf("socket connected...\n");



    return connect_fd ;

}


int SendFile ( const char * FileName , int connect_fd )
{

    // 打开需要发送的文件
    int fd = open( FileName , O_RDONLY );
    if (fd < 0 )
    {
        perror("open file error");
        return -1 ;
    }
    

    // 读取文件中的内容
    char * msg = calloc(MSG_LEN , 1 );
    int cont = 0 ;
    while(1)
    {
        int ret_val  = read( fd , msg , MSG_LEN );
        printf("readbyte:%d\n" , ret_val);
        if (ret_val <= 0 )
        {
            perror("read error");
            break ;
        }
        
        
        // 发送
        ret_val  =  send(connect_fd , msg , ret_val , 0 );
        printf("sendbyte:%d\n" , ret_val);

        cont += ret_val ;


    }

    sleep(1);

    // 发送结束标记告诉客户端发送结束
    send(connect_fd , "End Of File" , strlen("End Of File") , 0 );

    return cont ;

}
